#!/bin/python

# --------------------------------------
# VIDEO BUDDHA 2 - renamer
# --------------------------------------
# Ranames files based on user specified definitions.
# --------------------------------------

import ConfigParser
import os.path
import re
import sys
import time

import db.database
import file_info
import logger.logger

class Renamer:

	def __init__(self):
		self.expressions = ('(\d\d\d\d)|(\d\d\d)', '(\d\d)x(\d\d)', 's(\d\d)e(\d\d)', 'S(\d\d)E(\d\d)', '(\d)x(\d\d)') 
		self.config = ConfigParser.RawConfigParser()
		self.config.read('config.cfg')

		self.db = db.database.Database()
		self.logger = logger.logger.Logger()

		# Allowed extensions
		self.extensions = self.config.get('main', 'allowed_file_exts')
		self.extensions = self.extensions.split()
		
		# Directory
		self.dir = self.config.get('main', 'saved_dir')

		# Season episode format
		self.seas_ep_format = self.config.getint('main', 'seas_ep_format')

	def set_dir(self, dir):
		if os.path.exists(dir):
			self.dir = dir	    

			return True
		else:
			return False

	def get_files_list(self):
		''' Returns a list of FileInfo objects containing the path, file name and file 
		extension of each file in the directory. '''
			
		self.logger.log("Searching for video files in " + self.dir, self.logger.level[0])

		# All the files in the directory
		files = os.listdir(self.dir)

		# The list of the file_info objects
		file_infos = []

		# Run through all the files in the directory, if a video is found, append
		# a FileInfo object to the file_infos list and then return it after the loop
		for file in files:            
			file_ext = os.path.splitext(file)

			if file_ext[1] in self.extensions:
				# The cur_file_info is a new FileInfo object
				cur_file_info = file_info.FileInfo()
				cur_file_info.file_path = self.dir
				cur_file_info.file_name = file_ext[0]
				cur_file_info.extension = file_ext[1]                

				file_infos.append(cur_file_info)

				self.logger.log("\tVideo: " + cur_file_info.file_name + cur_file_info.extension, self.logger.level[0])

		# Only returns video files
		return file_infos

	def get_video_infos(self, file_infos):
		''' Return the file info object back with all the information from the
		matching file extensions '''
		defs = self.db.retrieve()

		# SHOW NAME
		# ---------
		# Loop through all the definitions to find a show name
		self.logger.log("Searching for video shows in the definitions database.", self.logger.level[0])
		for (id, oldname, newname) in defs:
			# Loop through all of the file_infos supplied
			for file_info in file_infos:
				# Check if the given file matches one of the definitions
				search = file_info.file_name.find(oldname)

				# Search found a match
				if search == 0:
					file_info.show_name = newname

					self.logger.log("\tMatch found for: " + newname + " from: " + file_info.file_name, self.logger.level[0])

		# SEASON EPISODE AND TRAIL
		# --------------
		# Loop through all the file_infos
		self.logger.log("Searching for season and episode information.", self.logger.level[0])
		for file_info in file_infos:
			# Loop through all the expressions to match season and episode info
			for expression in self.expressions:					
				found = re.search(expression, file_info.file_name)
				if found is not None:
					file_info.seas_ep = file_info.file_name[found.start():found.end()]
					file_info.trailing_info = file_info.file_name[found.end():]

					# This section removes any prefixed periods or such from the trail
					remove_chars = ['.', '_', '-', ')', ']',]
					if file_info.trailing_info[0:1] in remove_chars:
						file_info.trailing_info = file_info.trailing_info[1:]

					remove_phrases = [' - ', ' ::', ' //']
					if file_info.trailing_info[0:3] in remove_phrases:
						file_info.trailing_info = file_info.trailing_info[3:]

					self.logger.log("\tFound: " + file_info.seas_ep + " " + file_info.trailing_info, self.logger.level[0])

					# Prevent the program from looping back through and finding
					# false-positive matches
					break	

		# Will return the original list and any additions from matches
		# found using the definitions database
		return file_infos

	def format_seas_ep(self, file_infos):
		''' Format the season and episode information from the given file info objects '''
		self.config = ConfigParser.RawConfigParser()
		self.config.read('config.cfg')
		self.seas_ep_format = self.config.getint('main', 'seas_ep_format')
		
		# Loop through all the files
		for file_info in file_infos:
			# Make sure the file contains a seas_ep string, that is, there is a match
			# in the definitions database
			if file_info.seas_ep is not None:		
				# Run through all the expressions and convert the seas_ep to a universal
				# format so it can be easily converted to the user specified one
				for expression in self.expressions:
					seas_ep = file_info.seas_ep

					found = re.search(expression, seas_ep)
					if found is not None:									
						# Redo season episode format to a universal one
						# 000, or 0000
						if expression == self.expressions[0]:
							# Have to account for seas/ep info given in 3 digits
							if len(seas_ep) == 3:
								seas_ep = "s0" + seas_ep[0:1] + "e" + seas_ep[1:3]
							# ...or 4 digits
							if len(seas_ep) == 4:
								seas_ep = "s" + seas_ep[0:2] + "e" + seas_ep[2:4]
						# 0x00
						if expression == self.expressions[4]:
							seas_ep = "s" + seas_ep[0:2] + "e" + seas_ep[2:4]			

						# 00x00
						if expression == self.expressions[1]:
							seas_ep = "s" + seas_ep[0:2] + "e" + seas_ep[3:5]

						# s00e00
						if expression == self.expressions[2]:
							seas_ep = "s" + seas_ep[1:3] + "e" + seas_ep[4:6]						

						# S00E00
						if expression == self.expressions[3]:
							seas_ep = "s" + seas_ep[1:3] + "e" + seas_ep[4:6]

						# All seas_ep info is now in s01e01 format, can be converted from here
						seas_ep_format = self.seas_ep_format
						# 0000, 000
						if seas_ep_format == 4:
							seas_ep = seas_ep[2:3] + seas_ep[4:6]
						# S01E01
						elif seas_ep_format == 2:
							seas_ep = "S" + seas_ep[1:3] + "E" + seas_ep[4:6]
						# 01x01
						elif seas_ep_format == 3:
							seas_ep = seas_ep[1:3] + "x" + seas_ep[4:6]
						# s01e01
						elif seas_ep_format == 1:
							# Already this format
							pass
						else:
							seas_ep = "s" + seas_ep[1:3] + "e" + seas_ep[4:6]

						file_info.seas_ep = seas_ep
						break

		return file_infos

	def format_new_name(self, file_infos):
		self.config = ConfigParser.RawConfigParser()
		self.config.read('config.cfg')		
		
		for file_info in file_infos:
			formated = self.config.get('main', 'rename_format')
			if file_info.show_name is not None:
				renamed = formated.replace('%t', file_info.show_name)
				
				if file_info.seas_ep is not None:
					renamed = renamed.replace('%se', file_info.seas_ep)
	
				# Trailing bullshit
				renamed = renamed.replace('%i', file_info.trailing_info)
	
				file_info.new_name = renamed

		return file_infos

	def get_complete_file_infos(self):		
		file_infos = self.get_files_list()
		file_infos = self.get_video_infos(file_infos)
		file_infos = self.format_seas_ep(file_infos)
		file_infos = self.format_new_name(file_infos)

		return file_infos

	def rename(self, file_infos):
		renamed_count = 0
		
		for file_info in file_infos:
			if file_info.new_name is not None:
				try:
					src = os.path.join(file_info.file_path, file_info.file_name + file_info.extension)
					dest = os.path.join(file_info.file_path, file_info.new_name + file_info.extension)

					os.rename(src, dest)
					
					renamed_count += 1

				except OSError:
					self.logger.log("Could not rename file +\n\tSrc: " + src + "\n\tDest: " + dest, self.logger.level[4])
				
		return renamed_count